package com.cecurs.bigexcel;

import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import sun.misc.BASE64Encoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * Copyright: Copyright (c) 2020 cecurs
 *
 * @ClassName: FileDownloadUtil
 * @Description: 该类的功能描述
 * @version: v1.0.0
 * @author: zhaohaidong
 * @date: 2020/4/20 0020 14:47
 * <p>
 * Modification History:
 * Date         Author          Version            Description
 * ---------------------------------------------------------*
 * 2020/4/20 0020     zhaohaidong           v1.0.0               修改原因
 */
public class FileDownloadUtil {
    /**
     * 编译下载的文件名
     *
     * @param filename
     * @param agent
     * @return
     * @throws IOException
     */
    public static String encodeDownloadFilename(String filename, String agent) throws IOException {
        // 火狐浏览器
        if (agent.contains( "Firefox" )) {
            filename = "=?UTF-8?B?"
                    + new BASE64Encoder().encode( filename.getBytes( "utf-8" ) )
                    + "?=";
            filename = filename.replaceAll( "\r\n", "" );
        } else { // IE及其他浏览器
            filename = URLEncoder.encode( filename, "utf-8" );
            filename = filename.replace( "+", " " );
        }
        return filename;
    }

    /**
     * 设置下载excel的响应头信息
     *
     * @param response
     * @param request
     * @param fileName
     * @throws IOException
     */
    public static void setExcelHeadInfo(HttpServletRequest request, HttpServletResponse response, String fileName) {
        try {
            // 获取客户端浏览器的类型
            String agent = request.getHeader( "User-Agent" );
            // 对文件名重新编码
            String encodingFileName = encodeDownloadFilename( fileName + ".xlsx", agent );
            // 告诉客户端允许断点续传多线程连接下载
            response.setHeader( "Accept-Ranges", "bytes" );
            //文件后缀
            response.setContentType( "application/vnd.ms-excel;charset=UTF-8" );
            response.setHeader( "Content-Disposition", "attachment; filename=" + encodingFileName );
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置下载zip的响应头信息
     *
     * @param response
     * @param fileName 文件名
     * @param request
     * @throws IOException
     */
    public static void setZipDownLoadHeadInfo(HttpServletRequest request, HttpServletResponse response, String fileName) throws IOException {
        // 获取客户端浏览器的类型
        String agent = request.getHeader( "User-Agent" );
        response.setContentType( "application/octet-stream;charset=UTF-8" );
        // 表示不能用浏览器直接打开
        response.setHeader( "Connection", "close" );
        // 告诉客户端允许断点续传多线程连接下载
        response.setHeader( "Accept-Ranges", "bytes" );
        // 对文件名重新编码
        String encodingFileName = encodeDownloadFilename( fileName + ".zip", agent );
        response.setHeader( "Content-Disposition", "attachment; filename=" + encodingFileName );
    }

    /**
     * 下载
     *
     * @param response
     * @param workBooks
     * @param zipThreshold
     */
    public static void downLoad(HttpServletRequest request, HttpServletResponse response, List<SXSSFWorkbook> workBooks, int zipThreshold, String fileName) {
        //声明输出流
        OutputStream outputStream = null;
        //响应到客户端
        try {
            //获取输出流
            outputStream = response.getOutputStream();
            // 设置响应头
            if (zipThreshold == -1) {
                setExcelHeadInfo( request, response, fileName );
                //用文档写输出流
                workBooks.get( 0 ).write( outputStream );
                //刷新输出流
                outputStream.flush();
                outputStream.close();
            } else {
                setZipDownLoadHeadInfo( request, response, fileName );
                //创建临时文件
                File zipTempFile = File.createTempFile( fileName, ".zip" );
                zipFiles( workBooks, zipTempFile, fileName );
                FileInputStream inputStream = new FileInputStream( zipTempFile );
                BufferedInputStream bins = new BufferedInputStream( inputStream );
                BufferedOutputStream bouts = new BufferedOutputStream( outputStream );
                int bytesRead = 0;
                byte[] buffer = new byte[8192];
                //开始向网络传输文件流
                while ((bytesRead = bins.read( buffer, 0, 8192 )) != -1) {
                    bouts.write( buffer, 0, bytesRead );
                }
                bouts.flush();// 这里一定要调用flush()方法
                inputStream.close();
                bins.close();
                outputStream.close();
                bouts.close();
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭输出流
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void zipFiles(List<SXSSFWorkbook> workbooks, File zipfile, String fileName) {
        try {
            // Create the ZIP file
            ZipOutputStream out = new ZipOutputStream( new FileOutputStream( zipfile ) );
            // Compress the files
            for (int i = 0; i < workbooks.size(); i++) {
                SXSSFWorkbook workbook = workbooks.get( i );
                // Add ZIP entry to output stream.
                out.putNextEntry( new ZipEntry( fileName + i + ".xlsx" ) );
                // Transfer bytes from the file to the ZIP file
                workbook.write( out );
                //刷新输出流
                // Complete the entry
                out.closeEntry();
            }
            // Complete the ZIP file
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
